#include "../include/PrimitiveNode.hpp"
using namespace klas;

#include <iostream>
using namespace std;

PrimitiveNode::PrimitiveNode()
{
	m_rot = 0.0;
	m_scale = 1.0;
	m_ID = INVALID_ID;
	m_shouldRender = true;
}

PrimitiveNode::PrimitiveNode(const Vector2<Real>& pos, const Rectangle<Real>& rect, const Color& col)
{
	m_rot = 0.0;
	m_scale = 1.0;
	m_ID = INVALID_ID;
	m_shouldRender = true;
	
	setPos(pos);
	
	Point pt;
	pt.col = col;
	
	pt.pos = rect.getPos();
	addPoint(pt);
	
	pt.pos.x = rect.x + rect.w;
	addPoint(pt);
	
	pt.pos.y = rect.y + rect.h;
	addPoint(pt);
	
	pt.pos.x = rect.x;
	addPoint(pt);
}

PrimitiveNode::PrimitiveNode(const Vector2<Real>& center, Real radius,
		const Color& col, iReal accuracy)
{
	m_rot = 0.0;
	m_scale = 1.0;
	m_ID = INVALID_ID;
	
	setPos(center);
	
	Point pt;
	pt.col = col;
	Vector2<Real> nextPos;
	for(iReal i = 0; i < 360; i += accuracy)
	{
		Real degInRad = i * (KLAS_PI / 180.0);
		nextPos.x = cos(degInRad)*radius;
		nextPos.y = sin(degInRad)*radius;
		nextPos += center;
		pt.pos = nextPos;
		pt.pos -= center;
		addPoint(pt);
	}
	
	/* or 
		use a quad strip

		for (int i = 0; i < 360; i+=10)
		{
		glVertex2f( sin(i*DEG2RAD) * outer_dist, cos(i*DEG2RAD) * outer_dist );
		glVertex2f( sin(i*DEG2RAD) * inner_dist, cos(i*DEG2RAD) * inner__dist );

		}
	*/
}

PrimitiveNode::PrimitiveNode(const Vector2<Real>& pos, const Point& ptA, const Point& ptB)
{
	m_rot = 0.0;
	m_scale = 1.0;
	m_ID = INVALID_ID;
	
	setPos(pos);
	
	addPoint(ptA);
	addPoint(ptB);
}

PrimitiveNode::PrimitiveNode(const Vector2<Real>& pos, const Point& ptA, const Point& ptB, const Point& ptC)
{
	m_rot = 0.0;
	m_scale = 1.0;
	m_ID = INVALID_ID;
	
	setPos(pos);
	
	addPoint(ptA);
	addPoint(ptB);
	addPoint(ptC);
}

PrimitiveNode::~PrimitiveNode()
{
	m_pts.clear();
}

PrimitiveNode* PrimitiveNode::getDeepCopy()
{
	PrimitiveNode* node = new PrimitiveNode();
	node->m_rot = m_rot;
	node->m_scale = m_scale;
	node->m_ID = m_ID;
	node->m_rect.setPos(m_rect.getPos());
	node->m_rect.setDim(m_rect.getDim());
	node->m_prevRect.setPos(m_prevRect.getPos());
	node->m_prevRect.setDim(m_prevRect.getDim());
	node->m_pts = m_pts;
	node->m_center = m_center;
	node->m_baseColor = m_baseColor;

	return node;
}

iReal PrimitiveNode::addPoint(const Point& pt, uint8 flags)
{
	if((flags & ADD_FRONT) != 0)
	{
		m_pts.push_front(pt);
		recalculateCenter();
		return 0;
	}
	
	m_pts.push_back(pt);
	recalculateCenter();
	return m_pts.size();
}

void PrimitiveNode::changeColor(const Color& col, iReal idx)
{
	// if we have a negative index, change the color of every nodes
	if(idx < 0)
	{
		for(list<Point>::iterator it = m_pts.begin(); it != m_pts.end(); ++it)
			it->col = col;
	
		return;
	}
	
	if(idx > iReal(m_pts.size()))
		return;
	
	// find and change the color of the point.
	list<Point>::iterator it = m_pts.begin();
	for(iReal i = 0; i < idx; ++i)
		++it;
	it->col = col;
}


void rotate2D(float angle, float pointOfRotationX, float pointOfRotationY)
{
	// Note that the steps here are in the reverse order of that mentioned above!!
	// That's because openGL transformations post-multiply the matrices.
	glTranslatef(pointOfRotationX, pointOfRotationY, 0.0f);
	glRotatef(angle, 0.0f, 0.0f, 1.0f);
	glTranslatef(-pointOfRotationX, -pointOfRotationY, 0.0f);
}

void PrimitiveNode::render(const Rectangle<Real>& camera)
{
  if(m_shouldRender == false)
    return;
    
	glPushMatrix();
	glDisable(GL_TEXTURE_2D);
	
	
	rotate2D(m_rot, m_rect.x - camera.x, m_rect.y - camera.y);
	glTranslated(m_rect.x - (m_center.x * m_scale), m_rect.y - (m_center.y * m_scale), 0.0);
	
	// What type of shape do we have?
	if(m_pts.size() == 2)
		glBegin(GL_LINES);
	else if(m_pts.size() == 3)
		glBegin(GL_TRIANGLES);
	else if(m_pts.size() == 4)
		glBegin(GL_QUADS);
	else
		glBegin(GL_POLYGON);
	
	for(list<Point>::const_iterator it = m_pts.begin(); it != m_pts.end(); ++it)
	{
	  // Set the color of the point.
		glColor4d(it->col.getR(), it->col.getG(), it->col.getB(), it->col.getA());
		
		// Scale the node, and render it, too.
		glVertex3d((it->pos.x * m_scale) - camera.x, (it->pos.y * m_scale) - camera.y, 0.0f);
	}
	glEnd();
	
	glEnable(GL_TEXTURE_2D);
	glPopMatrix();
}

void PrimitiveNode::recalculateCenter()
{
	m_center.zero();
	for(list<Point>::const_iterator it = m_pts.begin(); it != m_pts.end(); ++it)
	{
		m_center += (it->pos / m_pts.size());
	}
	//cout << "center.x: " << m_center.x << " center.y: " << m_center.y << endl; 
}

iReal PrimitiveNode::getNodeType() const
{
	return Node::PRIMITIVE;
}
